﻿#include "FITKSeparatePlate.h"
#include "FITK_Kernel/FITKCore/FITKVec3D.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementTri.h"
#include <QQueue>

namespace Interface
{
    FITKSeparatePlate::FITKSeparatePlate() 
    {
        m_mesh = new FITKPlateMesh;
    }
    FITKSeparatePlate::~FITKSeparatePlate() 
    {
        if (!m_mesh) delete m_mesh;
    }

    QList<QList<int>> FITKSeparatePlate::getPlates(const QList<Core::FITKNode*>& meshPoints, const QList<Interface::FITKAbstractElement*>& meshFaces)
    {
        //初始化板网格
        this->initPlatesMesh(meshPoints, meshFaces);
        //返回每个板及板组成的面
        return this->getPlatesFace();
    }

    bool FITKSeparatePlate::initPlatesMesh(const QList<Core::FITKNode*>& meshPoints, const QList<Interface::FITKAbstractElement*>& meshFaces)
    {
        if (meshPoints.empty() || meshFaces.empty()) return false;

        //对网格对象的数据清理
        m_mesh->clear();
        //记录网格点的容器
        std::vector<FITKPlateMesh::VertexHandle> vhandles{};
        //记录面顶点的容器
        std::vector<FITKPlateMesh::VertexHandle> face_vhandles{};
        //记录网格点的id
        QList<int> node_id{};

        //添加点
        for (QList<Core::FITKNode*>::const_iterator it = meshPoints.begin(); it != meshPoints.end(); it++)
        {
            FITKPlateMesh::Point m_point((*it)->x(), (*it)->y(), (*it)->z());
            //存储网格点的id
            node_id.append((*it)->getNodeID());
            vhandles.push_back(m_mesh->add_vertex(m_point));
        }

        //添加面
        for (QList<Interface::FITKAbstractElement*>::const_iterator it = meshFaces.begin(); it != meshFaces.end(); ++it)
        {
            face_vhandles.clear();
            //判断是否是（Tri3,Tri6,Quad4,Quad8,Polygon, 三角形、4.6.8.n边形）拓扑单元类型
            if (!((*it)->getEleType() == FITKModelEnum::FITKEleType::Tri3
                || (*it)->getEleType() == FITKModelEnum::FITKEleType::Tri6
                || (*it)->getEleType() == FITKModelEnum::FITKEleType::Quad4
                || (*it)->getEleType() == FITKModelEnum::FITKEleType::Quad8
                || (*it)->getEleType() == FITKModelEnum::FITKEleType::Polygon))
                return false;

            //获取点的id,加入到面顶点的容器中
            for (int i = 0; i < (*it)->getNodeCount(); i++)
            {
                //根据点的ID获取所在的索引
                int node_index = node_id.indexOf((*it)->getNodeID(i));
                if (node_index < 0 || node_index >= vhandles.size()) continue;
                face_vhandles.push_back(vhandles[node_index]);
            }

            //添加面
            if (face_vhandles.size() < 3) continue;

            m_mesh->add_face(face_vhandles);
        }
        return true;
    }

    void FITKSeparatePlate::SeparatePlate(QVector<bool>& usedFace, QList<int>& plateFaces)
    {
        //面队列
        QQueue<OpenMesh::FaceHandle> face_queue{};
        //初始化种子面
        if (usedFace.indexOf(false) < 0) return;
        OpenMesh::FaceHandle seed_face = m_mesh->face_handle(usedFace.indexOf(false));
        //将种子面添加到队列
        face_queue.enqueue(seed_face);
        //对应种子面的id设置为已访问
        usedFace[seed_face.idx()] = true;

        while (!face_queue.empty())
        {
            //获取队首面
            OpenMesh::FaceHandle face = face_queue.front();
            //将队首面移除
            face_queue.dequeue();
            //将面添加到组成该块板的面中
            plateFaces.append(face.idx());

            for (FITKPlateMesh::FaceHalfedgeIter it = m_mesh->fh_iter(OpenMesh::FaceHandle(face)); it.is_valid(); it++)
            {
                //获取当前半边的对立半边
                OpenMesh::HalfedgeHandle opp_edge = m_mesh->opposite_halfedge_handle(*it);
                //跳过边界半边
                if (m_mesh->is_boundary(opp_edge)) continue;
                //获取相邻面
                OpenMesh::FaceHandle neighbor_face = m_mesh->face_handle(opp_edge);
                //如果相邻面有效且未访问过，加入队列和已访问集合
                if (usedFace[neighbor_face.idx()]) continue;
                //对应相邻面的id设置为已访问
                usedFace[neighbor_face.idx()] = true;
                //将相邻面添加到队列
                face_queue.enqueue(neighbor_face);
            }
        }
    }

    QList<QList<int>> FITKSeparatePlate::getPlatesFace()
    {
        //记录已访问过的面索引
        QVector<bool> used_face(m_mesh->n_faces(), false);
        //存储所有板及组成板的面
        QList<QList<int>> all_plates{};

        for (FITKPlateMesh::FaceIter it = m_mesh->faces_begin(); it != m_mesh->faces_end(); it++)
        {
            if (used_face[it->idx()] == true) continue;
            //存储组成板的面
            QList<int> plate_face{};
            //获取板的所有面
            this->SeparatePlate(used_face, plate_face);
            //保存当前板
            if (plate_face.size() < 1)continue;
            all_plates.push_back(plate_face);
        }
        return all_plates;
    }
}